import logging
import time
import random
from typing import List
from functional import seq
from ...constants.common_sequence import SWITCH_ENV
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
from ...constants.common_sequence import START_CLASS_KEYBOARD, LANGUAGE_SEQUENCE, DineCate
from ...exception.customer_exception import CustomerException
from ...models.enums.app_http_code_enum import AppHttpCodeEnum
from ...page.pay_page.pay_out_page import PayOutPage
from ...models.domain.order_desc import OrderDesc
from ...function.common_function import CommonFunction
from ...page.security_page.activity_page import ActivityPage
from ...page.security_page.coupon_page import CouponSearchPage


# 可以根据数量进行随机选择菜品，可以根据菜品名称和数量进行选择菜品
# TODO 需要可以指定小料，规格
# TODO random_add_to_cart（随机添加购物车套餐配置）


class OrderPage(object):
    """
    Description:下单页
    """

    def __init__(self, client):
        self.client = client
        self.driver = client.driver
        self.width = client.width
        self.height = client.height

    """
    Service Function
    """

    def time_sleep(self, second):
        """
        时间睡眠
        Params:
        -second:睡眠时间
        """
        time.sleep(second)
        return self

    def screen_shoot(self, filename, path):
        """
        屏幕截图
        Params:
        -filename:文件名称
        -path:路径
        """
        CommonFunction(self.driver).screen_shoot(filename=filename, path=path)
        return self

    def move_to_top(self):
        """
        到顶部（用于打开商品页面之后的返回顶部）
        """
        screen_size = self.driver.get_window_size()
        width = screen_size['width']
        height = screen_size['height']
        element_right = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/fragment_right')
        element_width = element_right.size['width']
        self.driver.swipe(start_x=width - element_width / 2, start_y=height / 2,
                          end_x=width - element_width / 2,
                          end_y=height, duration=50)

    def select_setmeal(self):
        """
        选中套餐后的处理逻辑
        """

        def slice_setmeal():
            """
            套餐分片的情况梳理
            """
            top_text = ''
            count = 0
            first_index, sec_index = None, None
            for record in child_names:
                class_name = record.get_attribute("class")
                if class_name == 'android.widget.LinearLayout' and count == 0:
                    top_text = record.find_element(AppiumBy.XPATH,
                                                   f".//*[contains(@resource-id,'{SWITCH_ENV}:id/tv_title')]").text
                    count += 1
                    first_index = child_names.index(record)
                    continue
                if class_name == 'android.widget.LinearLayout' and count == 1:
                    sec_index = child_names.index(record)
                    break
            # 如果第二个大标题不存在那么默认为第一个大标题位置
            sec_index = sec_index if sec_index else first_index
            return top_text, first_index, sec_index

        # 进行页面滑动选择商品
        old_top_text = ''
        while True:
            self.driver.implicitly_wait(10)
            child_names = self.driver.find_elements(AppiumBy.XPATH, f"//*[contains(@resource-id,'{SWITCH_ENV}:id/recyclerView')]/*")
            top_text, first_index, sec_index = slice_setmeal()
            # 这里是一直向上拖动到拖动不行，且后续无可选择分类
            if old_top_text != '' and len(list(set(old_top_text).difference(set(top_text)))) == 1 and list(set(old_top_text).difference(set(top_text)))[0].isdigit() and first_index == sec_index:
                break
            switch_tag = False
            if top_text.split('(')[0] in old_top_text:
                # 此情况一定是在原始页拖拽上去无变动的情况,但是有多个分类
                select_setmeal = child_names[sec_index + 1:]
            else:
                switch_tag = True
                old_top_text = top_text
                select_setmeal = child_names[first_index + 1:] if first_index == sec_index else child_names[first_index + 1:sec_index]
            if sec_index is not None:
                start = top_text.find("/")  # 找到 `/` 的位置
                end = top_text.find(")")  # 找到 `)` 的位置
                if start != -1 and end != -1:
                    result = int(top_text[start + 1:end])
                    numbers = random.sample(range(0, len(select_setmeal)), result)
                    for i in numbers:
                        self.driver.implicitly_wait(5)
                        # 刷新元素
                        child_names = self.driver.find_elements(AppiumBy.XPATH, f"//*[contains(@resource-id,'{SWITCH_ENV}:id/recyclerView')]/*")
                        if switch_tag:
                            select_setmeal = child_names[first_index + 1:] if first_index == sec_index else child_names[first_index + 1:sec_index]
                        else:
                            select_setmeal = child_names[sec_index + 1:]
                        select_setmeal[i].click()
                        self.driver.implicitly_wait(1)
                        try:
                            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_confirm').click()
                        except Exception:
                            print("此商品无需选择小料！跳过")
            # 页面移动
            screen_size = self.driver.get_window_size()
            width = screen_size['width']
            height = screen_size['height']
            element_right = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/fragment_right')
            element_width = element_right.size['width']
            self.driver.swipe(start_x=width - element_width / 2, start_y=height / 2,
                              end_x=width - element_width / 2,
                              end_y=height / 2 - height / 3, duration=1500)

    """
     PopUp Function
    """

    def start_class_test(self):
        """
        开班
        """
        # TODO 更适合兼容性操作，需要再次修复
        # 判断是否有开班窗口
        content = self.driver.find_element(AppiumBy.XPATH,
                                           f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/tv_title"]').text
        assert content in ["开班"]
        # 钱箱余额
        balance_account_desc = self.driver.find_element(AppiumBy.XPATH,
                                                        f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/tv_balance"]').text
        balance_account_list = list(str(balance_account_desc.split(": ")[1].strip()))
        element = self.driver.find_element(AppiumBy.XPATH,
                                           f'//android.view.View[@resource-id="{SWITCH_ENV}:id/keyboard"]')
        width, height = element.size["width"], element.size["height"]
        location_x, location_y = element.location["x"], element.location["y"]
        actions = ActionChains(self.driver)
        actions.w3c_actions = ActionBuilder(self.driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
        for num in balance_account_list:
            print(num)
            if num.isdigit() and num != 0:
                num = int(num)
                # 添加点击事件
                # 计算位置
                position_x_tag, position_y_tag = num % 3, num / 3 + 1
                if position_x_tag == 0:
                    position_x_tag = 3
                if num % 3 == 0:
                    position_y_tag = num / 3
                x, y = int(location_x + (position_x_tag - 1) * (width / 3)), int(
                    location_y + (position_y_tag - 1) * (height / 5))
            elif num == 0:
                x, y = int(location_x + width / 3), int(location_y + (width / 4) * 3)
            else:
                # 是小数点
                x, y = int(location_x), int(location_y + (width / 4) * 3)
            print(x, y)
            actions.w3c_actions.pointer_action.move_to_location(x, y)
            actions.w3c_actions.pointer_action.pointer_down()
            actions.w3c_actions.pointer_action.pause(0.1)
            actions.w3c_actions.pointer_action.release()
            actions.perform()
            time.sleep(1)

    def start_class(self, money=None):
        """
        开班
        """
        # TODO 需要进行配置多语言
        # 判断是否有开班窗口
        content = self.driver.find_element(AppiumBy.XPATH,
                                           f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/tv_title"]').text
        assert content in ["开班"]
        # 钱箱余额
        balance_account_desc = self.driver.find_element(AppiumBy.XPATH,
                                                        f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/tv_balance"]').text
        balance_account_list = list(str(balance_account_desc.split(": ")[1].strip()))
        if money is None:
            money_list = balance_account_list
        else:
            money_list = list(str(money))

        # 先清除数据
        for count in range(14):
            CommonFunction(self.driver).click_the_point(x=1497, y=981)
        # 再输入数值
        for record in money_list:
            value = None
            for key in START_CLASS_KEYBOARD:
                if record == key:
                    value = START_CLASS_KEYBOARD[key]
                    break
            CommonFunction(self.driver).click_the_point(**value)
        # 确认进行开班
        self.driver.find_element(AppiumBy.XPATH,
                                 f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/btn_confirm"]').click()
        # 判断是否导致异常开班
        error_tag = self.driver.find_element(AppiumBy.XPATH,
                                             f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/title"]').text
        if error_tag == "异常报备":
            self.error_class()

    def error_class(self):
        """
        异常开班（这里的异常原因是随机取的值）
        """
        error_reasons = self.driver.find_elements(AppiumBy.XPATH,
                                                  f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/tvOption"]')
        random_number = random.randint(0, len(error_reasons) - 1)
        error_reasons[random_number].click()

        self.driver.find_element(AppiumBy.XPATH,
                                 f'//android.widget.TextView[@resource-id="{SWITCH_ENV}:id/btn_confirm"]').click()

    def random_add_to_cart(self, count: int):
        """
        添加购物车
        Params:
        -count:数量
        """
        for record in range(count):
            for num in range(4):
                random.choice([self.pre_page, self.next_page])
            # 每次循环需要进行重新渲染
            goods_list = self.driver.find_elements(AppiumBy.XPATH,
                                                   f"//*[contains(@resource-id,'{SWITCH_ENV}:id/cv_item_view')]")
            random_num = random.randint(1, len(goods_list))
            goods_list[random_num - 1].click()
            print(goods_list[random_num - 1].find_element(AppiumBy.XPATH,
                                                          f'//*[@resource-id="{SWITCH_ENV}:id/tv_goods_name"]').text)
            try:
                self.move_to_top()
                setmeal_tag = self.driver.find_elements(AppiumBy.XPATH, f'//*[@resource-id="{SWITCH_ENV}:id/ll_standard"]/*[@resource-id="{SWITCH_ENV}:id/tv_title"]')
                if len(setmeal_tag) > 0:
                    setmeal_tag_text = setmeal_tag[0].text
                    if '/' in setmeal_tag_text:
                        self.select_setmeal()
                self.driver.implicitly_wait(2)
                self.driver.find_element(AppiumBy.XPATH,
                                         f'//android.widget.LinearLayout[@resource-id="{SWITCH_ENV}:id/ll_confirm"]').click()
            except Exception as e:
                CommonFunction(self.driver).screen_shoot()
        return self

    def goods_add_to_cart(self, good_list: List):
        """
        Desc：添加商品到购物车
        Params:
        -good_list:商品列表
        """
        try:
            text = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_page_index_total').text
            total_page = int(text.split('/')[1].strip())

            click_goods_num = 0
            for page in range(total_page):
                for record in good_list:
                    break_tag = False
                    if break_tag:
                        break
                    # 获取商品点击的次数
                    for i in range(record.number):
                        try:
                            element = self.driver.find_element(AppiumBy.XPATH,
                                                               f"//*[contains(@resource-id,'{SWITCH_ENV}:id/tv_goods_name') and @text='{record.name}' ]")
                            element.click()
                            self.move_to_top()
                            setmeal_tag = self.driver.find_elements(AppiumBy.XPATH, f'//*[@resource-id="{SWITCH_ENV}:id/ll_standard"]/*[@resource-id="{SWITCH_ENV}:id/tv_title"]')
                            if len(setmeal_tag) > 0:
                                setmeal_tag_text = setmeal_tag[0].text
                                if '/' in setmeal_tag_text:
                                    self.select_setmeal()
                            self.driver.implicitly_wait(2)
                            self.driver.find_element(AppiumBy.XPATH,
                                                     f'//android.widget.LinearLayout[@resource-id="{SWITCH_ENV}:id/ll_confirm"]').click()
                            click_goods_num += 1
                            self.driver.implicitly_wait(1)
                        except Exception as e:
                            logging.error(msg=f"{record.name}不在第({page + 1})页或选择改套餐时出现了问题！")
                if click_goods_num != sum(seq(good_list).map(lambda r: r.number).to_list()):
                    self.next_page()
                    self.driver.implicitly_wait(2)
                else:
                    break_tag = True
                    break
                if page == total_page - 1:
                    break_tag = True
                    break
        except Exception as e:
            raise CustomerException(AppHttpCodeEnum.INSERT_SHOPPING_CHART_FILE)
        return self

    """
    Button Function
    """

    def turn_to_activity(self):
        """
        切换至活动页
        """
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/rl_activity_list').click()
        return ActivityPage(self.client)

    def direct_payment(self):
        """
        直接支付
        """
        try:
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_cart_cashier').click()
        except Exception as e:
            raise CustomerException(AppHttpCodeEnum.DIRECT_PAY_FILE)
        return PayOutPage(self.client)

    def behind_payment(self):
        """
        后付
        """
        behind_payment = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/rl_enviar_cocina')
        behind_payment.click()
        return self

    def open_casher_machine(self):
        """
        打开钱箱
        """
        casher_machine = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_cart_abrir_caja')
        casher_machine.click()

    def remove_chart(self):
        """
        清空购物车
        """
        try:
            remove_element = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_cart_del')
            remove_element.click()
            self.driver.implicitly_wait(1)
            tv_sure_element = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_sure')
            tv_sure_element.click()
        except Exception as e:
            raise CustomerException(AppHttpCodeEnum.REMOVE_CHART_FILE)
        return self

    # TODO 切换语言时可以根据速度进行选择
    def switch_language(self, language):
        """
        切换语言
        """
        # 找到切换语言的按钮,并点击
        self.driver.find_element(AppiumBy.ID, value=f"{SWITCH_ENV}:id/iv_language").click()
        self.driver.implicitly_wait(2)
        # 切换语言
        element = self.driver.find_element(AppiumBy.ID, value=f"{SWITCH_ENV}:id/pickerview")
        # 获取宽和高
        height = element.size['height']

        # NODE 先回到最顶层，是通过时间进行控制的
        self.driver.swipe(self.width / 2, self.height - height / 2, self.width / 2,
                          self.height - height / 2 + height / 5, duration=100)  # duration 以毫秒为单位
        index = LANGUAGE_SEQUENCE.index(language)
        # NOTE 移动滑块
        for i in range(index):
            self.driver.swipe(self.width / 2, self.height - height / 2, self.width / 2,
                              self.height - height / 2 - height / 5, duration=500)  # duration 以毫秒为单位

        time.sleep(1)
        # 点击确认
        self.driver.find_element(AppiumBy.ID, value=f"{SWITCH_ENV}:id/tv_confirm").click()
        time.sleep(3)

    def log_out(self):
        """
        登出
        """
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/iv_user').click()
        self.driver.implicitly_wait(1)
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_sure').click()

    def next_page(self):
        """
        下一页
        """
        next_page_elements = self.driver.find_elements(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_next_page')
        if len(next_page_elements) != 1:
            raise CustomerException(AppHttpCodeEnum.GOODS_NEXT_PAGE_FILE)
        else:
            next_page_elements[0].click()
        return self

    def pre_page(self):
        """
        上一页
        """
        pre_page_element = self.driver.find_elements(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_previous_page')
        if len(pre_page_element) != 1:
            raise CustomerException(AppHttpCodeEnum.GOODS_PRE_PAGE_FILE)
        else:
            pre_page_element[0].click()
        return self

    def switch_category(self, category: str):
        """
        切换分类
        """
        for i in range(5):
            element = self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_dining_methods')
            element.click()
            if category == element.text:
                return self

    def order_desc_manual(self, desc: OrderDesc):
        """
        订单备注（手动填写）
        """
        name, telephone, address, desc, type1 = desc.name, desc.telephone, desc.address, desc.desc, desc.type
        # 点击订单备注
        if type1 == DineCate.takeout.value:
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_order_detail').click()
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_name').send_keys(name.strip())  # 姓名
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_telephone').send_keys(
                telephone.strip())  # 电话号码
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_address').send_keys(
                address.strip())  # 地址
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_note').send_keys(desc.strip())  # 描述
        if type1 == DineCate.dinein.value:
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_order_detail').click()
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_name').send_keys(name.strip())  # 姓名
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_telephone').send_keys(
                telephone.strip())  # 电话号码
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_note').send_keys(desc.strip())  # 描述
        if type1 == DineCate.askfor.value:
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_note').send_keys(desc.strip())  # 描述
        # 点击确定
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_confirm').click()
        self.driver.implicitly_wait(3)
        return self

    def order_desc_auto(self, desc: OrderDesc):
        """
        订单备注（自动填写）
        """
        telephone, desc = desc.telephone, desc.desc
        # 点击订单备注
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_order_detail').click()
        # 填入手机号
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_telephone').send_keys(telephone.strip())
        # 搜索
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_search_user_address').click()
        self.driver.implicitly_wait(2)
        # 选择某一项,默认选择第一项
        try:
            self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/cb_select').click()
        except Exception as e:
            logging.log(level=logging.ERROR, msg="手机号未注册会员！")
            # 失去焦点
            CommonFunction(self.driver).click_the_point(x=156, y=219)
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/et_note').send_keys(desc.strip())
        # 点击确定
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_confirm').click()

    def print_detail(self):
        """
        打印队列（详情）
        """
        # 打开打印队列
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_print_status').click()
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_printing_fail').click()  # 失败队列
        CommonFunction(self.driver).screen_shoot()
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/tv_printing_success').click()  # 成功队列
        CommonFunction(self.driver).screen_shoot()

    def using_coupon(self):
        """
        使用优惠券
        """
        self.driver.find_element(AppiumBy.ID, f'{SWITCH_ENV}:id/useCouponButton').click()
        return CouponSearchPage(self.client)
